package cn.udrm.elasticsearch.service;

import cn.udrm.elasticsearch.model.Article;
import cn.udrm.elasticsearch.util.Md5CaculateUtil;
import io.searchbox.client.JestClient;
import io.searchbox.core.Index;
import io.searchbox.core.Search;
import io.searchbox.core.SearchResult;
import lombok.extern.slf4j.Slf4j;
import net.sf.jmimemagic.*;
import net.sf.json.JSONObject;
import org.apache.poi.hwpf.extractor.WordExtractor;
import org.apache.poi.xwpf.extractor.XWPFWordExtractor;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.List;
import java.util.UUID;

@Component
@Slf4j
public class DirectoryRecurse2 {

    @Autowired
    private JestClient jestClient;

    private  int total=0;

    //读取文件内容转换为字符串
    public String readToString(File file, String fileType) {
        StringBuffer result = new StringBuffer();
        switch (fileType) {
            case "text/plain":
            case "java":
            case "c":
            case "cpp":
            case "txt":
                try (FileInputStream in = new FileInputStream(file)) {
                    Long filelength = file.length();
                    byte[] filecontent = new byte[filelength.intValue()];
                    in.read(filecontent);
                    result.append(new String(filecontent, "utf8"));
                } catch (FileNotFoundException e) {
                    log.error("{}", e.getLocalizedMessage());
                } catch (IOException e) {
                    log.error("{}", e.getLocalizedMessage());
                }
                break;
            case "doc":
                //使用HWPF组件中WordExtractor类从Word文档中提取文本或段落
                try (FileInputStream in = new FileInputStream(file)) {
                    WordExtractor extractor = new WordExtractor(in);
                    String[] texts=extractor.getParagraphText();
                    for(String text:texts){
                        result.append(text);
                    }
                } catch (Exception e) {
                    log.error("获取文件内容失败！", e);
                }
                break;
            case "docx":
                try (FileInputStream in = new FileInputStream(file)) {
                    XWPFDocument doc = new XWPFDocument(in);
                    XWPFWordExtractor extractor = new XWPFWordExtractor(doc);
                    result.append(extractor.getText());
                } catch (Exception e) {
                    log.error("{}", e.getLocalizedMessage());
                }
                break;
        }
        return result.toString();
    }

    //判断是否已经索引
    private JSONObject isIndex(File file) {
        JSONObject result = new JSONObject();
        //用MD5生成文件指纹,搜索该指纹是否已经索引
        String fileFingerprint = Md5CaculateUtil.getMD5(file);
        result.put("fileFingerprint", fileFingerprint);
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(QueryBuilders.termQuery("fileFingerprint", fileFingerprint));
        Search search = new Search.Builder(searchSourceBuilder.toString()).addIndex("diskfile").addType("files").build();
        try {
            //执行
            SearchResult searchResult = jestClient.execute(search);
            if(searchResult.isSucceeded()){
               // List<SearchResult.Hit<Article, Void>> hits = searchResult.getHits(Article.class);
                List<Article> articles = searchResult.getSourceAsObjectList(Article.class,false);
                if (articles!=null&&articles.size()>0) {
                    result.put("isIndex", true);
                } else {
                    result.put("isIndex", false);
                }
            }else{
                result.put("isIndex", false);
            }

        } catch (Exception e) {
            System.out.println("===========查询失败！=====");
            log.error("查询索引失败",e);
        }
        return result;
    }

    //对文件目录及内容创建索引
    private void createIndex(File file, String method) {
        //忽略掉临时文件，以~$起始的文件名
        if (file.getName().startsWith("~$")) return;

        String fileType = null;
        switch (method) {
            case "magic":
                Magic parser = new Magic();
                try {
                    MagicMatch match = parser.getMagicMatch(file, false);
                    fileType = match.getMimeType();
                } catch (MagicParseException e) {
                    //log.error("{}",e.getLocalizedMessage());
                } catch (MagicMatchNotFoundException e) {
                    //log.error("{}",e.getLocalizedMessage());
                } catch (MagicException e) {
                    //log.error("{}",e.getLocalizedMessage());
                }
                break;
            case "ext":
                String filename = file.getName();
                String[] strArray = filename.split("\\.");
                int suffixIndex = strArray.length - 1;
                fileType = strArray[suffixIndex];
        }

        switch (fileType) {
            case "text/plain":
            case "java":
            case "c":
            case "cpp":
            case "txt":
            case "doc":
            case "docx":
                JSONObject isIndexResult = isIndex(file);
                log.info("文件名：{}，文件类型：{}，MD5：{}，建立索引：{}", file.getPath(), fileType, isIndexResult.getString("fileFingerprint"), isIndexResult.getBoolean("isIndex"));

                if (isIndexResult.getBoolean("isIndex")) break;
                //1\. 给ES中索引(保存)一个文档
                Article article = new Article();
                article.setId(UUID.randomUUID().toString());
                article.setTitle(file.getName());
                article.setAuthor(file.getParent());
                article.setPath(file.getPath());
                article.setContent(readToString(file, fileType));
                article.setFileFingerprint(isIndexResult.getString("fileFingerprint"));
                //2\. 构建一个索引
                Index index = new Index.Builder(article).index("diskfile").type("files").build();
                try {
                    //3\. 执行
                    if (!jestClient.execute(index).getId().isEmpty()) {
                        log.info("构建索引成功！");
                    }
                } catch (IOException e) {
                    log.error("{}", e.getLocalizedMessage());
                }
                break;
        }
    }

    public void find(String pathName) throws Exception {
        //获取pathName的File对象
        File dirFile = new File(pathName);

        //判断该文件或目录是否存在，不存在时在控制台输出提醒
        if (!dirFile.exists()) {
            log.info("do not exit");
            return;
        }

        //判断如果不是一个目录，就判断是不是一个文件，时文件则输出文件路径
        if (!dirFile.isDirectory()) {
            if (dirFile.isFile()) {
                createIndex(dirFile, "ext");
            }
            return;
        }

        //获取此目录下的所有文件名与目录名
        String[] fileList = dirFile.list();
        for (int i = 0; i < fileList.length; i++) {
            //遍历文件目录
            String string = fileList[i];
            File file = new File(dirFile.getPath(), string);
            //如果是一个目录，输出目录名后，进行递归
            if (file.isDirectory()) {
                //递归
                find(file.getCanonicalPath());
            } else {
                log.info("========文件尚未建立索引==========");
                createIndex(file, "ext");
                total++;
                log.info("===========检索文件："+file.getName()+" 文件已检索："+total);
            }
        }
    }

    public void setTotal(int total) {
        this.total = total;
    }

    public int getTotal() {
        return total;
    }
}
